//! @file   lc_thread_manager.cpp
//! @brief  
//! @author Sayan Chaliha
//! @date   September, 2011
//!
//! 
#include <lc_thread_manager.h>

namespace cyan {
    ThreadManager ThreadManager::threadManager_;
    LinkedList<Thread*>* ThreadManager::activeThreads_;
    Mutex* ThreadManager::listMutex_;
    ConditionVariable* ThreadManager::listEmptyCondition_;
    ThreadStorage<Thread*>* ThreadManager::threadLocalRef_;
    
    ThreadManager::ThreadManager() {
        ThreadManager::activeThreads_ = new LinkedList<Thread*>;
        ThreadManager::listMutex_ = new Mutex;
        ThreadManager::listEmptyCondition_ = new
            ConditionVariable(*ThreadManager::listMutex_);
        ThreadManager::threadLocalRef_ = new ThreadStorage<Thread*>();
    }
    
    ThreadManager::~ThreadManager() {
        ThreadManager::listMutex_->lock();
        if (ThreadManager::activeThreads_->size() > 0)
            ThreadManager::listEmptyCondition_->wait(Interval::NO_TIMEOUT);
        delete ThreadManager::threadLocalRef_;
        delete ThreadManager::activeThreads_;
        ThreadManager::listMutex_->unlock();
        delete ThreadManager::listMutex_;
        delete ThreadManager::listEmptyCondition_;
    }
    
    ThreadManager* ThreadManager::getInstance() {
        return &ThreadManager::threadManager_;
    }

    Thread* ThreadManager::getContextualThread() {
        return ThreadManager::threadLocalRef_->data();
    }

    Bool ThreadManager::isContextualThreadPrimordial() {
        return ThreadManager::getContextualThread() != nullptr;
    }

    void ThreadManager::registerThread(Thread* thread) {
        CriticalSection section(*ThreadManager::listMutex_);
        ThreadManager::activeThreads_->pushBack(thread);
    }
    
    void ThreadManager::unregisterThread(Thread* thread) {
        CriticalSection section(*ThreadManager::listMutex_);
        if (ThreadManager::activeThreads_->size() != 0) {
            ThreadManager::activeThreads_->remove(thread);
            if (ThreadManager::activeThreads_->size() == 0) {
                ThreadManager::listEmptyCondition_->notify();
            }
        }
    }

    void ThreadManager::setLocalReference(Thread* thread) {
        ThreadManager::threadLocalRef_->data(thread);
    }
}
